//
//  NvAssetManager.m
//  SDKDemo
//
//  Created by dx on 2018/6/8.
//  Copyright © 2018年 meishe. All rights reserved.
//

#import "NvAssetManager.h"
#import "NvHttpRequest.h"
#import "NvUtils.h"
#import "ZipArchive.h"
#import "NvSDKUtils.h"
#define NV_CDN_URL              @"http://omxuaeaki.bkt.clouddn.com"
#define NV_DOMAIN_URL           @"https://meishesdk.meishe-app.com"

@interface NvAssetManager() <NvHttpRequestDelegate, NvsAssetPackageManagerDelegate>

@property (nonatomic, strong) NvsStreamingContext *streamingContext;

@end

@implementation NvUserAssetInfo

@end

@implementation NvCustomStickerInfo

@end

@implementation NvAssetManager {
    NvHttpRequest *networkManager;
    NSString *assetDownloadDirPathTheme;
    NSString *assetDownloadDirPathFilter;
    NSString *assetDownloadDirPathCaption;
    NSString *assetDownloadDirPathAnimatedSticker;
    NSString *assetDownloadDirPathTransition;
    NSString *assetDownloadDirPathCaptureScene;
    NSString *assetDownloadDirPathParticle;
    NSString *assetDownloadDirPathFaceSticker;
    NSString *assetDownloadDirPathCustomAnimatedSticker;
    NSString *assetDownloadDirPathFace1Sticker;
    BOOL isLocalAssetSearchedTheme;
    BOOL isLocalAssetSearchedFilter;
    BOOL isLocalAssetSearchedCaption;
    BOOL isLocalAssetSearchedAnimatedSticker;
    BOOL isLocalAssetSearchedTransition;
    BOOL isLocalAssetSearchedCaptureScene;
    BOOL isLocalAssetSearchedParticle;
    BOOL isLocalAssetSearchedFaceSticker;
    BOOL isLocalAssetSearchedCustomAnimatedSticker;
    BOOL isLocalAssetSearchedFace1Sticker;
}

static NvAssetManager *sharedInstance = nil;
+ (NvAssetManager *)sharedInstance {
    if (nil != sharedInstance) {
        return sharedInstance;
    }
    
    static dispatch_once_t pred;
    dispatch_once(&pred, ^{
        sharedInstance = [[NvAssetManager alloc] init];
    });
    
    return sharedInstance;
}

- (instancetype)init {
    self = [super init];
    self.assetDict = NSMutableDictionary.new;
    self.maxConcurrentAssetDownloadNum = 10;
    self.downloadingAssetsCounter = 0;
    self.pendingAssetsToDownload = NSMutableArray.new;
    assetDownloadDirPathTheme = [NvSDKUtils getAssetDownloadPath:ASSET_THEME];
    assetDownloadDirPathFilter = [NvSDKUtils getAssetDownloadPath:ASSET_FILTER];
    assetDownloadDirPathCaption = [NvSDKUtils getAssetDownloadPath:ASSET_CAPTION_STYLE];
    assetDownloadDirPathAnimatedSticker = [NvSDKUtils getAssetDownloadPath:ASSET_ANIMATED_STICKER];
    assetDownloadDirPathTransition = [NvSDKUtils getAssetDownloadPath:ASSET_VIDEO_TRANSITION];
    assetDownloadDirPathCaptureScene = [NvSDKUtils getAssetDownloadPath:ASSET_CAPTURE_SCENE];
    assetDownloadDirPathParticle = [NvSDKUtils getAssetDownloadPath:ASSET_PARTICLE];
    assetDownloadDirPathFaceSticker = [NvSDKUtils getAssetDownloadPath:ASSET_FACE_STICKER];
    assetDownloadDirPathCustomAnimatedSticker = [NvSDKUtils getAssetDownloadPath:ASSET_CUSTOM_ANIMATED_STICKER];
    assetDownloadDirPathFace1Sticker = [NvSDKUtils getAssetDownloadPath:ASSET_FACE1_STICKER];
    self.streamingContext = [NvsStreamingContext sharedInstance];
    self.streamingContext.assetPackageManager.delegate = self;
    self.remoteAssetsOrderedList = NSMutableDictionary.new;
    self.customStickerDict = NSMutableDictionary.new;
    self.isSyncInstallAsset = YES;
    [self initCustomStickersFromUserDefaults];
    
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillTerminate:) name:UIApplicationWillTerminateNotification object:nil];
    return self;
}

- (void)dealloc {
    [self setAssetInfoToUserDefaults];
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

- (void)applicationWillTerminate:(NSNotification*)notification {
    [self setAssetInfoToUserDefaults];
}

- (void)downloadRemoteAssetsInfo:(AssetType)assetType aspectRatio:(AspectRatio)aspectRatio categoryId:(int)categoryId page:(int)page pageSize:(int)pageSize {
    networkManager = [NvHttpRequest sharedInstance];
    [networkManager checkNetwork:self];
    [networkManager getAssetList:assetType aspectRatio:aspectRatio categoryId:categoryId page:page pageSize:pageSize withDelegate:self];
}

- (NSArray *)getRemoteAssets:(AssetType)assetType aspectRatio:(AspectRatio)aspectRatio categoryId:(int)categoryId {
    NSMutableArray *assets = self.remoteAssetsOrderedList[[NSString stringWithFormat:@"%d", assetType]];
    NSMutableArray *array = NSMutableArray.new;
    for (NSString *uuid in assets) {
        NvAsset *asset = [self findAsset:uuid];
        if (aspectRatio == AspectRatio_All && categoryId == NV_CATEGORY_ID_ALL) {
            [array addObject:asset];
        } else if (aspectRatio == AspectRatio_All && categoryId != NV_CATEGORY_ID_ALL) {
            if (asset.categoryId == categoryId)
                [array addObject:asset];
        } else if (aspectRatio != AspectRatio_All && categoryId == NV_CATEGORY_ID_ALL) {
            if ((asset.aspectRatio & aspectRatio) == aspectRatio)
                [array addObject:asset];
        } else {
            if ((asset.aspectRatio & aspectRatio) == aspectRatio && asset.categoryId == categoryId)
                [array addObject:asset];
        }
    }
    return array;
}

- (NSArray *)getUsableAssets:(AssetType)assetType aspectRatio:(AspectRatio)aspectRatio categoryId:(int)categoryId {
    NSMutableArray *assets = self.assetDict[[NSString stringWithFormat:@"%d", assetType]];
    
    NSArray *sortedAssets = [assets sortedArrayUsingComparator:^NSComparisonResult(NvAsset *  _Nonnull obj1, NvAsset * _Nonnull obj2) {
        NSDictionary *fileAttributes1 = [[NSFileManager defaultManager] attributesOfItemAtPath:[obj1 isReserved] ? obj1.bundledLocalDirPath : obj1.localDirPath
                                                                                         error:nil];
        
        NSDictionary *fileAttributes2 = [[NSFileManager defaultManager] attributesOfItemAtPath:[obj2 isReserved] ? obj2.bundledLocalDirPath : obj2.localDirPath
                                                                                         error:nil];
        NSDate *date1 = [fileAttributes1 objectForKey:NSFileCreationDate] ;
        NSDate *date2 = [fileAttributes2 objectForKey:NSFileCreationDate] ;
        if (date1 == nil)
            return YES;
        if (date2 == nil)
            return NO;
        return [date2 compare:date1];
    }];
    
    NSMutableArray *array = NSMutableArray.new;
    for (NvAsset *asset in sortedAssets) {
        if (aspectRatio == AspectRatio_All && categoryId == NV_CATEGORY_ID_ALL) {
            if ([asset isUsable])
                [array addObject:asset];
        } else if (aspectRatio == AspectRatio_All && categoryId != NV_CATEGORY_ID_ALL) {
            if (asset.categoryId == categoryId && [asset isUsable])
                [array addObject:asset];
        } else if (aspectRatio != AspectRatio_All && categoryId == NV_CATEGORY_ID_ALL) {
            if ((asset.aspectRatio & aspectRatio) == aspectRatio && [asset isUsable])
                [array addObject:asset];
        } else {
            if ((asset.aspectRatio & aspectRatio) == aspectRatio && asset.categoryId == categoryId && [asset isUsable])
                [array addObject:asset];
        }
    }
    
    return array;
}

- (NSArray *)getReservedAssets:(AssetType)assetType aspectRatio:(AspectRatio)aspectRatio categoryId:(int)categoryId {
    NSMutableArray *assets = self.assetDict[[NSString stringWithFormat:@"%d", assetType]];
    NSMutableArray *array = NSMutableArray.new;
    for (NvAsset *asset in assets) {
        if (aspectRatio == AspectRatio_All && categoryId == NV_CATEGORY_ID_ALL) {
            if ([asset isUsable] && [asset isReserved])
                [array addObject:asset];
        } else if (aspectRatio == AspectRatio_All && categoryId != NV_CATEGORY_ID_ALL) {
            if (asset.categoryId == categoryId && [asset isUsable] && [asset isReserved])
                [array addObject:asset];
        } else if (aspectRatio != AspectRatio_All && categoryId == NV_CATEGORY_ID_ALL) {
            if ((asset.aspectRatio & aspectRatio) == aspectRatio && [asset isUsable] && [asset isReserved])
                [array addObject:asset];
        } else {
            if ((asset.aspectRatio & aspectRatio) == aspectRatio && asset.categoryId == categoryId && [asset isUsable] && [asset isReserved])
                [array addObject:asset];
        }
    }
    return array;
}

- (DownloadStatus)getAssetDownloadStatus:(NSString *)uuid {
    NvAsset *asset = [self findAsset:uuid];
    if (asset == nil)
        return DownloadStatusNone;
    return asset.downloadStatus;
}

- (int)getAssetDownloadProgress:(NSString *)uuid {
    NvAsset *asset = [self findAsset:uuid];
    if (asset == nil)
        return 0;
    return (int)(asset.downloadProgress*100 +.5f);
}

- (NvAsset *)getAsset:(NSString *)uuid {
    return [self findAsset:uuid];
}

- (BOOL)downloadAsset:(NSString *)uuid {
    NvAsset *asset = [self findAsset:uuid];
    if (asset == nil) {
        NSLog(@"Invalid asset uuid %@", uuid);
        return NO;
    }
    if (![asset hasRemoteAsset]) {
        NSLog(@"Asset '%@' doesn't have a remote url!", uuid);
        return NO;
    }
    switch (asset.downloadStatus) {
        case DownloadStatusNone:
        case DownloadStatusFinished:
        case DownloadStatusFailed:
            break;
        case DownloadStatusPending:
            NSLog(@"Asset '%@' has already in pending download state!", uuid);
            return NO;
        case DownloadStatusInProgress:
            NSLog(@"Asset '%@' is being downloaded right now!", uuid);
            return NO;
        case DownloadStatusDecompressing:
            NSLog(@"Asset '%@' is being uncompressed right now!", uuid);
            return NO;
        default:
            NSLog(@"Invalid status for Asset '%@'!", uuid);
            return NO;
    }
    
    [self.pendingAssetsToDownload addObject:uuid];
    asset.downloadStatus = DownloadStatusPending;
    [self downloadPendingAsset];
    
    return YES;
}

- (void)downloadPendingAsset {
    while (self.downloadingAssetsCounter < self.maxConcurrentAssetDownloadNum && _pendingAssetsToDownload.count) {
        NSString *uuid = [_pendingAssetsToDownload lastObject];
        [_pendingAssetsToDownload removeLastObject];
        if (![self startDownloadAsset:uuid]) {
            NvAsset *asset = [self findAsset:uuid];
            asset.downloadStatus = DownloadStatusFailed;
            if ([self.delegate respondsToSelector:@selector(onDonwloadAssetFailed:)]) {
                [self.delegate onDonwloadAssetFailed:uuid];
            }
        }
    }
}

- (NSString *)getAssetDownloadDirPath:(AssetType)assetType {
    switch (assetType) {
        case ASSET_THEME:
            return assetDownloadDirPathTheme;
        case ASSET_FILTER:
            return assetDownloadDirPathFilter;
        case ASSET_CAPTION_STYLE:
            return assetDownloadDirPathCaption;
        case ASSET_ANIMATED_STICKER:
            return assetDownloadDirPathAnimatedSticker;
        case ASSET_VIDEO_TRANSITION:
            return assetDownloadDirPathTransition;
        case ASSET_CAPTURE_SCENE:
            return assetDownloadDirPathCaptureScene;
        case ASSET_PARTICLE:
            return assetDownloadDirPathParticle;
        case ASSET_FACE_STICKER:
            return assetDownloadDirPathFaceSticker;
        case ASSET_CUSTOM_ANIMATED_STICKER:
            return assetDownloadDirPathCustomAnimatedSticker;
        case ASSET_FACE1_STICKER:
            return assetDownloadDirPathFace1Sticker;
        default:
            break;
    }
    return @"";
}

- (BOOL)getIsLocalAssetSearched:(AssetType)assetType {
    switch (assetType) {
        case ASSET_THEME:
            return isLocalAssetSearchedTheme;
        case ASSET_FILTER:
            return isLocalAssetSearchedFilter;
        case ASSET_CAPTION_STYLE:
            return isLocalAssetSearchedCaption;
        case ASSET_ANIMATED_STICKER:
            return isLocalAssetSearchedAnimatedSticker;
        case ASSET_VIDEO_TRANSITION:
            return isLocalAssetSearchedTransition;
        case ASSET_CAPTURE_SCENE:
            return isLocalAssetSearchedCaptureScene;
        case ASSET_PARTICLE:
            return isLocalAssetSearchedParticle;
        case ASSET_FACE_STICKER:
            return isLocalAssetSearchedFaceSticker;
        case ASSET_CUSTOM_ANIMATED_STICKER:
            return isLocalAssetSearchedCustomAnimatedSticker;
        case ASSET_FACE1_STICKER:
            return isLocalAssetSearchedFace1Sticker;
        default:
            break;
    }
    return NO;
}

- (void)setIsLocalAssetSearched:(AssetType)assetType isSearched:(BOOL)isSearched {
    switch (assetType) {
        case ASSET_THEME:
            isLocalAssetSearchedTheme = isSearched;
            return;
        case ASSET_FILTER:
            isLocalAssetSearchedFilter = isSearched;
            return;
        case ASSET_CAPTION_STYLE:
            isLocalAssetSearchedCaption = isSearched;
            return;
        case ASSET_ANIMATED_STICKER:
            isLocalAssetSearchedAnimatedSticker = isSearched;
            return;
        case ASSET_VIDEO_TRANSITION:
            isLocalAssetSearchedTransition = isSearched;
            return;
        case ASSET_CAPTURE_SCENE:
            isLocalAssetSearchedCaptureScene = isSearched;
            return;
        case ASSET_PARTICLE:
            isLocalAssetSearchedParticle = isSearched;
            return;
        case ASSET_FACE_STICKER:
            isLocalAssetSearchedFaceSticker = isSearched;
            return;
        case ASSET_CUSTOM_ANIMATED_STICKER:
            isLocalAssetSearchedCustomAnimatedSticker = isSearched;
            return;
        case ASSET_FACE1_STICKER:
            isLocalAssetSearchedFace1Sticker = isSearched;
            return;
        default:
            break;
    }
}

- (BOOL)startDownloadAsset:(NSString *)uuid {
    NvAsset *asset = [self findAsset:uuid];
    if (asset == nil) {
        NSLog(@"Invalid asset uuid %@", uuid);
        return NO;
    }
    if (![asset hasRemoteAsset]) {
        NSLog(@"Asset '%@' doesn't have a remote url!", uuid);
        return NO;
    }
    
    NSAssert(asset.downloadStatus == DownloadStatusPending, @"download asset failed!");
    NSString *assetDownloadDirPath = [self getAssetDownloadDirPath:asset.assetType];
    if ([NvUtils isStringEmpty:assetDownloadDirPath])
        return NO;
    
    NvHttpRequest *httpRequest = [NvHttpRequest sharedInstance];
    asset.downloadTask = [httpRequest downloadAsset:[asset.remotePackageUrl absoluteString]
                   destFileDir:assetDownloadDirPath
                  withDelegate:self
                    downloadID:asset.uuid];
    
    _downloadingAssetsCounter++;
    asset.downloadProgress = 0;
    asset.downloadStatus = DownloadStatusInProgress;
    
    return YES;
}

- (BOOL)cancelAssetDownload:(NSString *)uuid {
    NvAsset *asset = [self findAsset:uuid];
    if (asset == nil) {
        NSLog(@"Invalid asset uuid %@", uuid);
        return NO;
    }
    switch (asset.downloadStatus) {
        case DownloadStatusPending:
            [_pendingAssetsToDownload removeObject:uuid];
            asset.downloadStatus = DownloadStatusNone;
            break;
        case DownloadStatusInProgress:
            [asset.downloadTask cancel];
            asset.downloadStatus = DownloadStatusNone;
            break;
        default:
            NSLog(@"You can't cancel downloading asset '%@' while it is not in any of the download states!", uuid);
            return NO;
    }
    return YES;
}

- (NvAsset *)findAsset:(NSString *)uuid {
    for (NSString *key in self.assetDict) {
        for (NvAsset *asset in self.assetDict[key]) {
            if ([asset.uuid isEqualToString:uuid]) {
                return asset;
            }
        }
    }
    return nil;
}

- (void)searchLocalAssets:(AssetType)assetType {
    if ([self getIsLocalAssetSearched:assetType])
        return;
    
    NSString *dirPath = [self getAssetDownloadDirPath:assetType];
    [self setAssetInPath:assetType dirPath:dirPath isReserved:NO];
    
    [self setIsLocalAssetSearched:assetType isSearched:YES];
}

- (void)searchReservedAssets:(AssetType)assetType bundlePath:(NSString *)bundlePath {
    [self setAssetInPath:assetType dirPath:bundlePath isReserved:YES];
}

- (void)setAssetInPath:(AssetType)assetType dirPath:(NSString *)dirPath isReserved:(BOOL)isReserved {
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSArray *array = [fileManager contentsOfDirectoryAtPath:dirPath error:nil];
    
    NSMutableArray *assets = self.assetDict[[NSString stringWithFormat:@"%d", assetType]];
    if (assets == nil) {
        assets = NSMutableArray.new;
        [self.assetDict setObject:assets forKey:[NSString stringWithFormat:@"%d", assetType]];
    }
    for (NSString *filename in array) {
        if ([filename containsString:@"png"] || [filename containsString:@"json"])
            continue;

        NvAsset *assetInfo = NvAsset.new;
        assetInfo.assetType = assetType;
        assetInfo.uuid = [[filename componentsSeparatedByString:@"."] firstObject];
        assetInfo.isReserved = isReserved;
        assetInfo.downloadStatus = DownloadStatusDecompressing;
        if (isReserved) {
            assetInfo.bundledLocalDirPath = [dirPath stringByAppendingPathComponent:filename];
        } else {
            assetInfo.localDirPath = [dirPath stringByAppendingPathComponent:filename];
        }
        
        [self installAsset:assetInfo];
        
        if (!isReserved) {
            NvUserAssetInfo *userAssetInfo = [self getAssetInfoFromUserDefaults:assetType uuid:assetInfo.uuid];
            assetInfo.coverUrl = [NSURL URLWithString:userAssetInfo.coverUrl];
            assetInfo.name = userAssetInfo.name;
            assetInfo.categoryId = userAssetInfo.categoryId;
            assetInfo.aspectRatio = userAssetInfo.aspectRatio;
            assetInfo.remotePackageSize = userAssetInfo.remotePackageSize;
        } else {
            NSString *suffix = @".png";
            if (assetInfo.assetType == ASSET_THEME)
                suffix = @".jpg";
            assetInfo.coverUrl = [NSURL URLWithString:[dirPath stringByAppendingPathComponent:[assetInfo.uuid stringByAppendingString:suffix]]];
            assetInfo.name = @"";
            assetInfo.categoryId = 1;
            assetInfo.aspectRatio = AspectRatio_All;
        }
        
        NvAsset *asset = [self findAsset:assetInfo.uuid];
        if (asset == nil) {
            [assets addObject:assetInfo];
        } else {
            if (asset.version < assetInfo.version) {
                [asset copyAsset:assetInfo];
            }
        }
    }
}

- (void)installAsset:(NvAsset *)assetInfo {
    if (assetInfo.assetType == ASSET_FACE1_STICKER) {
        NSString *filepath = assetInfo.isReserved ? assetInfo.bundledLocalDirPath : assetInfo.localDirPath;
        assetInfo.downloadStatus = DownloadStatusFinished;
        assetInfo.version = [NvSDKUtils getAssetVersionWithPath:filepath];
        
        if (assetInfo.isReserved) {
            NSString *coverString = [filepath stringByReplacingOccurrencesOfString:@".bundle" withString:@".png"];
            assetInfo.coverUrl = [NSURL URLWithString:coverString];
        }
    } else {
        NSMutableString *packageId = [[NSMutableString alloc] init];
        NSString *packagePath = assetInfo.isReserved ? assetInfo.bundledLocalDirPath : assetInfo.localDirPath;
        if (self.isSyncInstallAsset) {
            NvsAssetPackageManagerError error = [self.streamingContext.assetPackageManager installAssetPackage:packagePath
                                                              license:nil
                                                                 type:[assetInfo getPackageType]
                                                                 sync:YES
                                                       assetPackageId:packageId];
            if (error == NvsAssetPackageManagerError_NoError) {
                assetInfo.downloadStatus = DownloadStatusFinished;
                assetInfo.version = [self.streamingContext.assetPackageManager getAssetPackageVersion:assetInfo.uuid type:[assetInfo getPackageType]];
                assetInfo.aspectRatio = [self.streamingContext.assetPackageManager getAssetPackageSupportedAspectRatio:assetInfo.uuid type:[assetInfo getPackageType]];
            } else if (error == NvsAssetPackageManagerError_AlreadyInstalled) {
                assetInfo.downloadStatus = DownloadStatusFinished;
                assetInfo.version = [self.streamingContext.assetPackageManager getAssetPackageVersion:assetInfo.uuid type:[assetInfo getPackageType]];
                assetInfo.aspectRatio = [self.streamingContext.assetPackageManager getAssetPackageSupportedAspectRatio:assetInfo.uuid type:[assetInfo getPackageType]];
                int version = [self.streamingContext.assetPackageManager getAssetPackageVersionFromAssetPackageFilePath:packagePath];
                if (version > assetInfo.version) {
                    error = [self.streamingContext.assetPackageManager upgradeAssetPackage:packagePath
                                                                      license:nil
                                                                         type:[assetInfo getPackageType]
                                                                         sync:YES
                                                               assetPackageId:packageId];
                    if (error == NvsAssetPackageManagerError_NoError) {
                        assetInfo.version = assetInfo.version;
                    } else {
                        ;//升级素材失败，仍旧用老素材
                    }
                }
            } else {
                assetInfo.downloadStatus = DownloadStatusDecompressingFailed;
            }
        } else {
            if ([self.streamingContext.assetPackageManager getAssetPackageStatus:assetInfo.uuid type:[assetInfo getPackageType]]
                == NvsAssetPackageManagerError_AlreadyInstalled) {
                int version = [self.streamingContext.assetPackageManager getAssetPackageVersionFromAssetPackageFilePath:packagePath];
                if (version > assetInfo.version) {
                    [self.streamingContext.assetPackageManager upgradeAssetPackage:packagePath
                                                                      license:nil
                                                                         type:[assetInfo getPackageType]
                                                                         sync:NO
                                                               assetPackageId:packageId];
                }
            } else {
                [self.streamingContext.assetPackageManager installAssetPackage:packagePath
                                                                  license:nil
                                                                     type:[assetInfo getPackageType]
                                                                     sync:NO
                                                           assetPackageId:packageId];
            }
        }
    }
}

- (void)setAssetInfoToUserDefaults {
    NSUserDefaults *user = [NSUserDefaults standardUserDefaults];
    NSMutableDictionary *assetInfoDict = NSMutableDictionary.new;
    for (NSString *key in self.assetDict) {
        NSMutableDictionary *assetsDict = NSMutableDictionary.new;
        for (NvAsset *asset in self.assetDict[key]) {
            NSMutableDictionary *assetDict = NSMutableDictionary.new;
            [assetDict setObject:asset.name == nil ? @"" : asset.name forKey:@"name"];
            [assetDict setObject:asset.coverUrl == nil ? @"" : [asset.coverUrl absoluteString] forKey:@"coverUrl"];
            [assetDict setObject:[NSNumber numberWithInt:asset.categoryId] forKey:@"categoryId"];
            [assetDict setObject:[NSNumber numberWithInt:asset.aspectRatio] forKey:@"aspectRatio"];
            [assetDict setObject:[NSNumber numberWithInt:asset.remotePackageSize] forKey:@"remotePackageSize"];
            [assetsDict setObject:[NSMutableDictionary dictionaryWithDictionary:assetDict] forKey:asset.uuid];
        }
        [assetInfoDict setObject:[NSDictionary dictionaryWithDictionary:assetsDict] forKey:key];
    }
    [user setObject:[NSDictionary dictionaryWithDictionary:assetInfoDict] forKey:@"assetInfo"];
    
    NSMutableDictionary *stickersDict = NSMutableDictionary.new;
    for (NSString *key in self.customStickerDict) {
        NvCustomStickerInfo *info = self.customStickerDict[key];
        NSMutableDictionary *stickerDict = NSMutableDictionary.new;
        [stickerDict setObject:info.templateUuid forKey:@"templateUUID"];
        [stickerDict setObject:info.imagePath forKey:@"imagePath"];
        [stickerDict setObject:[NSNumber numberWithInt: info.order] forKey:@"order"];
        [stickersDict setObject:[NSMutableDictionary dictionaryWithDictionary:stickerDict] forKey:info.uuid];
    }
    [user setObject:[NSDictionary dictionaryWithDictionary:stickersDict] forKey:@"customStickers"];
}

- (NvUserAssetInfo *)getAssetInfoFromUserDefaults:(AssetType)assetType uuid:(NSString *)uuid {
    NSUserDefaults *user = [NSUserDefaults standardUserDefaults];
    NSDictionary *dict = [user objectForKey:@"assetInfo"];
    NSDictionary *assetsDict = dict[[NSString stringWithFormat:@"%d", assetType]];
    for (NSString *key in assetsDict) {
        if ([key isEqualToString:uuid]) {
            NSDictionary *assetDict = assetsDict[key];
            NvUserAssetInfo *assetInfo = NvUserAssetInfo.new;
            assetInfo.name = assetDict[@"name"];
            assetInfo.coverUrl = assetDict[@"coverUrl"];
            assetInfo.categoryId = [(NSNumber *)assetDict[@"categoryId"] intValue];
            assetInfo.aspectRatio = [(NSNumber *)assetDict[@"aspectRatio"] intValue];
            assetInfo.remotePackageSize = [(NSNumber *)assetDict[@"remotePackageSize"] intValue];
            return assetInfo;
        }
    }
    return nil;
}

- (void)initCustomStickersFromUserDefaults {
    NSUserDefaults *user = [NSUserDefaults standardUserDefaults];
    NSDictionary *stickersDict = [user objectForKey:@"customStickers"];
    for (NSString *key in stickersDict) {
        NSDictionary *stickerDict = stickersDict[key];
        NvCustomStickerInfo *info = NvCustomStickerInfo.new;
        info.uuid = key;
        info.templateUuid = stickerDict[@"templateUUID"];
        info.order = [(NSNumber *)stickerDict[@"order"] intValue];
        info.imagePath = stickerDict[@"imagePath"];
        NSFileManager *fileManager = [NSFileManager defaultManager];
        if ([fileManager fileExistsAtPath:info.imagePath]) {
            [self.customStickerDict setObject:info forKey:key];
        }
    }
}

- (void)addRemoteAssetData:(NSArray *)resultsArray assetType:(AssetType)assetType {
    NSMutableArray *assets = self.assetDict[[NSString stringWithFormat:@"%d", assetType]];
    if (assets == nil) {
        assets = NSMutableArray.new;
    }
    for (NSDictionary *dict in resultsArray) {
        NvAsset *assetInfo = NvAsset.new;
        assetInfo.assetType = assetType;
        if ([dict objectForKey:@"category"])
            assetInfo.categoryId = [[dict objectForKey:@"category"] intValue];
        if ([dict objectForKey:@"tags"])
            assetInfo.tags = [dict objectForKey:@"tags"];
        if ([dict objectForKey:@"packageSize"])
            assetInfo.remotePackageSize = [[dict objectForKey:@"packageSize"] intValue];
        if ([dict objectForKey:@"id"])
            assetInfo.uuid = [dict objectForKey:@"id"];
        if ([dict objectForKey:@"minAppVersion"])
            assetInfo.minAppVersion = [dict objectForKey:@"minAppVersion"];
        if ([dict objectForKey:@"packageUrl"])
            assetInfo.remotePackageUrl = [NSURL URLWithString:[[dict objectForKey:@"packageUrl"] stringByReplacingOccurrencesOfString:NV_DOMAIN_URL withString:NV_CDN_URL]];
        if ([dict objectForKey:@"version"])
            assetInfo.remoteVersion = [[dict objectForKey:@"version"] intValue];
        if ([dict objectForKey:@"coverUrl"])
            assetInfo.coverUrl = [NSURL URLWithString:[[dict objectForKey:@"coverUrl"] stringByReplacingOccurrencesOfString:NV_DOMAIN_URL withString:NV_CDN_URL]];
        if ([dict objectForKey:@"supportedAspectRatio"])
            assetInfo.aspectRatio = [[dict objectForKey:@"supportedAspectRatio"] intValue];
        if ([dict objectForKey:@"name"])
            assetInfo.name = [dict objectForKey:@"name"];
        if ([dict objectForKey:@"desc"])
            assetInfo.desc = [dict objectForKey:@"desc"];
        
        NvAsset *asset = [self findAsset:assetInfo.uuid];
        if (asset == nil) {
            [assets addObject:assetInfo];
        } else {
            asset.categoryId = assetInfo.categoryId;
            asset.name = assetInfo.name;
            asset.coverUrl = assetInfo.coverUrl;
            asset.aspectRatio = assetInfo.aspectRatio;
            asset.remotePackageSize = assetInfo.remotePackageSize;
            asset.remoteVersion = assetInfo.remoteVersion;
        }
    }
    [self.assetDict setObject:assets forKey:[NSString stringWithFormat:@"%d", assetType]];
}

- (void)addRemoteAssetOrderedList:(NSArray *)resultsArray assetType:(AssetType)assetType {
    NSMutableArray *assets = self.remoteAssetsOrderedList[[NSString stringWithFormat:@"%d", assetType]];
    if (assets == nil) {
        assets = NSMutableArray.new;
    }
    for (NSDictionary *dict in resultsArray) {
        NSString *uuid = [dict objectForKey:@"id"];
        if (![self isUuidExistInRemoteOrderedList:assetType uuid:uuid]) {
            [assets addObject:uuid];
        }
    }
    [self.remoteAssetsOrderedList setObject:assets forKey:[NSString stringWithFormat:@"%d", assetType]];
}

- (BOOL)isUuidExistInRemoteOrderedList:(AssetType)assetType uuid:(NSString *)uuid {
    NSMutableArray *assets = self.remoteAssetsOrderedList[[NSString stringWithFormat:@"%d", assetType]];
    if (assets == nil)
        return NO;
    
    for (NSString *assetId in assets) {
        if ([uuid isEqualToString:assetId])
            return YES;
    }
    return NO;
}

#pragma mark NvHttpRequestDelegate

- (void)onGetAssetListSuccess:(NSArray *)resultsArray assetType:(AssetType)assetType hasNext:(BOOL)hasNext {
    [self addRemoteAssetData:resultsArray assetType:assetType];
    [self addRemoteAssetOrderedList:resultsArray assetType:assetType];
    
    if ([self.delegate respondsToSelector:@selector(onRemoteAssetsChanged:)]) {
        [self.delegate onRemoteAssetsChanged:hasNext];
    }
}

- (void)onGetAssetListFailed:(NSError *)error assetType:(AssetType) assetType {
    if ([self.delegate respondsToSelector:@selector(onGetRemoteAssetsFailed)]) {
        [self.delegate onGetRemoteAssetsFailed];
    }
}

- (void)onCheckNetworkState:(BOOL)isNetAvailable {
    if ([self.delegate respondsToSelector:@selector(onCheckNetworkState:)]){
        [self.delegate onCheckNetworkState:isNetAvailable];
    }
}

- (void)onDonwloadAssetProgress:(int32_t)progress downloadID:(NSString*)downloadID{
    if ([self.delegate respondsToSelector:@selector(onDownloadAssetProgress:progress:)]) {
        [self.delegate onDownloadAssetProgress:downloadID progress:progress];
    }
}
- (void)onDonwloadAssetSuccess:(BOOL)isSuccess downloadFilePath:(NSString*)downloadFilePath downloadID:(NSString*)downloadID{
    _downloadingAssetsCounter--;
    NvAsset *asset = [self findAsset:downloadID];
    asset.downloadProgress = 1;
    asset.downloadStatus = DownloadStatusDecompressing;
    downloadFilePath = [downloadFilePath stringByReplacingOccurrencesOfString:@"file://" withString:@""];
    asset.localDirPath = downloadFilePath;
    
    [self installAsset:asset];
    
    if ([self.delegate respondsToSelector:@selector(onDonwloadAssetSuccess:)]) {
        [self.delegate onDonwloadAssetSuccess:downloadID];
    }
    [self setAssetInfoToUserDefaults];
}
- (void)onDonwloadAssetFailed:(NSError *) error downloadFilePath:(NSString*)downloadFilePath downloadID:(NSString*)downloadID{
    if ([self.delegate respondsToSelector:@selector(onDonwloadAssetFailed:)]) {
        [self.delegate onDonwloadAssetFailed:downloadID];
    }
}

- (void)didFinishAssetPackageInstallation:(NSString *)assetPackageId filePath:(NSString *)assetPackageFilePath type:(NvsAssetPackageType)assetPackageType error:(NvsAssetPackageManagerError)error {
    if (error == NvsAssetPackageManagerError_NoError || error == NvsAssetPackageManagerError_AlreadyInstalled) {
        NvAsset *asset = [self findAsset:assetPackageId];
        asset.downloadStatus = DownloadStatusFinished;
        asset.version = [self.streamingContext.assetPackageManager getAssetPackageVersion:assetPackageId type:assetPackageType];
        asset.aspectRatio = [self.streamingContext.assetPackageManager getAssetPackageSupportedAspectRatio:asset.uuid type:[asset getPackageType]];
    } else {
        NvAsset *asset = [self findAsset:assetPackageId];
        asset.downloadStatus = DownloadStatusDecompressingFailed;
    }
    if ([self.delegate respondsToSelector:@selector(onFinishAssetPackageInstallation:)]) {
        [self.delegate onFinishAssetPackageInstallation:assetPackageId];
    }
}

- (void)didFinishAssetPackageUpgrading:(NSString *)assetPackageId filePath:(NSString *)assetPackageFilePath type:(NvsAssetPackageType)assetPackageType error:(NvsAssetPackageManagerError)error {
    if (error == NvsAssetPackageManagerError_NoError || error == NvsAssetPackageManagerError_AlreadyInstalled) {
        NvAsset *asset = [self findAsset:assetPackageId];
        asset.downloadStatus = DownloadStatusFinished;
        asset.version = [self.streamingContext.assetPackageManager getAssetPackageVersion:assetPackageId type:assetPackageType];
        asset.aspectRatio = [self.streamingContext.assetPackageManager getAssetPackageSupportedAspectRatio:asset.uuid type:[asset getPackageType]];
    } else {
        NvAsset *asset = [self findAsset:assetPackageId];
        asset.downloadStatus = DownloadStatusDecompressingFailed;
    }
    if ([self.delegate respondsToSelector:@selector(onFinishAssetPackageUpgrading:)]) {
        [self.delegate onFinishAssetPackageUpgrading:assetPackageId];
    }
}

- (NvsStreamingContext *)streamingContext {
    return [NvSDKUtils getSDKContext];
}

@end
